﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NFit.Core.Errors;

namespace NFit.Core
{
    /// <summary>
    /// Status of a RunnableElement
    /// </summary>
    public class Status
    {
        /// <summary>
        /// Indicate wether the element execution was successful
        /// </summary>
        public bool? Success { get; set; }

        private NFitError _nestedError;
        /// <summary>
        /// The nested execution error 
        /// </summary>
        public NFitError NestedError
        {
            get { return _nestedError; }
            set { _nestedError = value; }
        }

        /// <summary>
        /// Indicate if the element was runned
        /// </summary>
        public bool WasRunned
        {
            get
            {
                return Success.HasValue;
            }
        }

        /// <summary>
        /// Indicate if the execution is successful
        /// </summary>
        public bool IsSuccessful
        {
            get
            {
                return WasRunned && Success.Value;
            }
        }

        /// <summary>
        /// The date and time at wich the execution start
        /// </summary>
        public DateTime? StartTime
        {
            get;
            internal set;
        }

        /// <summary>
        /// The date and time at wich the execution end
        /// </summary>
        public DateTime? EndTime
        {
            get;
            internal set;
        }

        /// <summary>
        /// The duration of the execution
        /// </summary>
        public TimeSpan Duration
        {
            get
            {
                if (!StartTime.HasValue || !EndTime.HasValue)
                    return TimeSpan.Zero;

                return (EndTime.Value - StartTime.Value);
            }
        }

        /// <summary>
        /// Indicate if the status has an error of the provided type
        /// </summary>
        /// <typeparam name="T">The type of the error to search for</typeparam>
        /// <returns>true if the status has an error of that type</returns>
        public bool HasError<T>() where T : NFitError
        {
            if (NestedError != null && NestedError.GetType() == typeof(T))
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// Indicate if the status has an error of the provided type and that match the predicate
        /// </summary>
        /// <typeparam name="T">The type of the error to search for</typeparam>
        /// <param name="checkError"></param>
        /// <returns>true if the status has an error of that type and matching the predicate</returns>
        public bool HasError<T>(Predicate<T> checkError) where T : NFitError
        {            
            if (HasError<T>())
            {
                T err = (T) NestedError;
                if (checkError == null || checkError(err))
                {
                    return true;
                }
            }
            return false;
        }


    }
}
